package com.lin.csdn.dao;

import com.lin.csdn.utils.BaseLogger;
import com.lin.csdn.utils.PoolConnection;
import com.lin.csdn.utils.PoolDataSource;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseDao {

    BaseLogger baseLogger=new BaseLogger();
    PoolDataSource pool = new PoolDataSource();


    public List<Object> find(String sql, List<Object> params, Class cls) {
        List<Object> data = new ArrayList<>();
        Connection con = null;
        try {
            con = pool.getConnection();
        } catch (SQLException e) {
            baseLogger.infoLog("数据库连接失败");
        }
        PoolConnection connection=new PoolConnection(con, pool);
        Object value = null;
        PreparedStatement preparedStatement;
        ResultSet resultSet;

        try {
            con = connection.getRealConnection();
            preparedStatement = con.prepareStatement(sql);
            if (params != null && params.size() > 0) {
                // 循环设置参数，设置参数类型为Object
                for (int i = 0; i < params.size(); i++) {
                    preparedStatement.setObject(i + 1, params.get(i));
                }
            }
            // 执行查询，返回结果集
            resultSet = preparedStatement.executeQuery();
            // 判断并分析结果集
            // 得到结果集的元数据对象（查询到的字段数量以及查询了哪些字段）
            ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
            // 得到查询的字段数量
            int fieldNum = resultSetMetaData.getColumnCount();
            // 判断并分析结果集
            while (resultSet.next()) {
                // 创造空的实例对象
                Object object = cls.newInstance();
                // 遍历查询的字段数量，得到数据库中查询的每一个列名
                for (int i = 1; i <= fieldNum; i++) {
                    // 得到查询的每一个列名
                    // getColumnName()：获取列名
                    String columnName = resultSetMetaData.getColumnLabel(i);
                    // 通过反射，使用列名得到对应的field对象
                    Field field;
                    try {
                        field = cls.getDeclaredField(columnName);
                    } catch (Exception exception) {
                        continue;
                    }
                    // 拼接set方法，得到字符串
                    String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
                    // 通过反射，将set方法字符串反射成类中对应的set方法
                    Method method = cls.getDeclaredMethod(setMethod, field.getType());
                    //对两个常用的类型进行分类加入，防止参数与函数类型冲突
                    if (String.valueOf(field.getType()).equals("int")) {
                        value = resultSet.getInt(columnName);
                    }
                    else if (String.valueOf(field.getType()).equals("class java.lang.String")) {
                        value = resultSet.getString(columnName);
                    }
                    // 通过invoke方法调用set方法
                    method.invoke(object, value);
                }
                // 将Javabean设置到集合中
                data.add(object);
            }

        } catch (Exception e) {
            baseLogger.errorLog(String.valueOf(e));
        } finally {
            try {
               con.close();
            } catch (SQLException e) {
                baseLogger.errorLog(String.valueOf(e));
            }
        }
        return data;

    }


    //更新数据
    public int update(String sql, List<Object> params) {
        int id = 0;
        Connection con = null;
        try {
            con = pool.getConnection();
        } catch (SQLException e) {
            baseLogger.warningLog("数据库连接失败");
        }
        PoolConnection connection=new PoolConnection(con,pool);
        PreparedStatement preparedStatement;

        try {
            // 得到数据库连接
            con = connection.getRealConnection();
            // 预编译
            preparedStatement = con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            // 如果有参数，则设置参数，下标从1开始
            if (params != null && params.size() > 0) {
                // 循环设置参数，设置参数类型为Object
                for (int i = 0; i < params.size(); i++){
                    preparedStatement.setObject(i+1, params.get(i));
                }
            }
            // 执行更新，返回受影响的行数
            preparedStatement.executeUpdate();
            ResultSet rs=preparedStatement.getGeneratedKeys();
                if(rs.next()){
                    id=rs.getInt(1);
                }
        } catch (Exception e) {
            baseLogger.errorLog(String.valueOf(e));
        } finally {
            // 关闭资源
            try {
                con.close();
            } catch (SQLException e) {
                baseLogger.errorLog(String.valueOf(e));
            }
        }

        return id;
    }

    public Object findSingle(String sql, List<Object> params) {
        Object object = null;
        Connection con = null;
        try {
            con = pool.getConnection();
        } catch (SQLException e) {
            baseLogger.infoLog("数据库连接失败");
        }
        PoolConnection connection=new PoolConnection(con,pool);
        PreparedStatement preparedStatement;
        ResultSet resultSet;

        try {
            // 获取数据库连接
            con = connection.getRealConnection();
            // 预编译
            preparedStatement = con.prepareStatement(sql);
            // 如果有参数，则设置参数，下标从1开始
            if (params != null && params.size() > 0) {
                // 循环设置参数，设置参数类型为Object
                for (int i = 0; i < params.size(); i++){
                    preparedStatement.setObject(i+1, params.get(i));
                }
            }
            // 执行查询，返回结果集
            resultSet = preparedStatement.executeQuery();
            // 判断并分析结果集
            if (resultSet.next()) {
                object = resultSet.getObject(1);
            }

        } catch (Exception e) {
            baseLogger.errorLog(String.valueOf(e));
        } finally {
            // 关闭资源
            try {
                con.close();
            } catch (SQLException e) {
                baseLogger.errorLog(String.valueOf(e));
            }
        }

        return object;
    }
}
